//
// Created by xsh on 2025/5/25.
//

#include <SLES/OpenSlES.h>
#include <SLES/OpenSLES_Platform.h>
#include <SLES/OpenSLES_Android.h>
#include <jni.h>
#include <iostream>
#include <string>
#include <iomanip> // 用于控制输出精度
#include <android/log.h>
#include <dlfcn.h>
#include <math.h>
#include <cmath>
#include <functional>
#include "audio_common.h"
#include "slengine.h"
#include "LogUtil.h"
#include "native_engine.h"

const char* enginetag = "OpenSLES";
SlEngine engine;
// 引擎初始化和销毁
void SlEngine::initEngine()
{
    SLAndroidSimpleBufferQueueItf playerBufferQueue;
    CallbackContext *ctx = nullptr;
    // 创建引擎
    SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    if(result !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, enginetag, "slCreateEngine failed");
    }
    SLresult engineRealize = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    if(engineRealize !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "engineRealize failed");
    }
    SLresult engineInterFace = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    if(engineInterFace !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "engineInterFace failed");
    }
    // 创建混音器
    SLObjectItf outputMixObject;
    SLresult outputMix = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
    if(outputMix !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "CreateOutputMix failed");
    }
    SLresult outputMixRealize = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if(outputMixRealize !=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "outputMixRealize failed");
    }

    // 配置音频参数
    // 定义 PCM 参数
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
            2 // 缓冲区数量
    };

    SLDataFormat_PCM format_pcm = {
            SL_DATAFORMAT_PCM,
            2,                  // 声道数2 对应 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_SAMPLINGRATE_48, // 采样率 44100Hz
            SL_PCMSAMPLEFORMAT_FIXED_16, // 16位采样
            SL_PCMSAMPLEFORMAT_FIXED_16,
            //SL_SPEAKER_FRONT_CENTER,
            SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN
    };

    SLDataSource audioSrc = {&loc_bufq, &format_pcm};

    SLDataLocator_OutputMix loc_outmix = {
            SL_DATALOCATOR_OUTPUTMIX,
            outputMixObject
    };
    SLDataSink audioSnk = {&loc_outmix, NULL};

    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    //创建播放器
    SLresult resultAudioPlayer = (*engineEngine)->CreateAudioPlayer(
            engineEngine,
            &playerObj,// 改成engineObject试试 Error:createAudioPlayer failed
            &audioSrc,
            &audioSnk,
            1, ids, req
    );
    if(resultAudioPlayer!=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "createAudioPlayer failed");
    }
    //
    (*playerObj)->Realize(playerObj, SL_BOOLEAN_FALSE);
    (*playerObj)->GetInterface(playerObj, SL_IID_PLAY, &playerPlay);
    if((*playerObj)->GetInterface(playerObj,SL_IID_VOLUME,&volumeItf)!=SL_RESULT_SUCCESS)
    {
        LOGE("OpenSLES","Volume interface not supported!");
    }else{
        (*volumeItf)->GetMaxVolumeLevel(volumeItf,&maxLevel);
        minLevel = SL_MILLIBEL_MIN;
        setVolume(1.0f); // 初始化为最大音量
    }

    SLresult  getBufferQueueResult = (*playerObj)->GetInterface(playerObj, SL_IID_BUFFERQUEUE, &playerBufferQueue);
    if(getBufferQueueResult!=SL_RESULT_SUCCESS){
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "GetInterface(BUFFERQUEUE) failed: %d", getBufferQueueResult);
    }
    ctx = new CallbackContext ();
    ctx->currentPhase = 0.0;
    ctx->pcmBuffer = new short[samplesPerBuffer];// 分配缓冲区内存
    SLresult  regResult = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, engineQueueCallback, ctx);
    if(regResult!=SL_RESULT_SUCCESS)
    {
        __android_log_print(ANDROID_LOG_ERROR, "OpenSLES", "RegisterCallback failed: %d", regResult);
    }
    engineQueueCallback(playerBufferQueue, ctx); // 第一次填充
    engineQueueCallback(playerBufferQueue, ctx); // 第二次填充
    LOGD(enginetag,"引擎初始化完毕");
}
void SlEngine::destoryEngine()
{
    (*playerObj)->Destroy(playerObj);
    (*engineObject)->Destroy(engineObject);
}
// 缓冲队列回调函数
void SlEngine::engineQueueCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    CallbackContext* ctx = (CallbackContext*)context;
    if(engine.activeInstrument)
    {
        ctx->currentPhase = engine.activeInstrument->genWave(ctx->pcmBuffer,samplesPerBuffer,ctx->currentPhase,sampleRate);
    }

    // 处理所有等待的 MIDI 消息 2025/6/4
    /*for (const auto& msg : engine->midiQueue) {
        if (msg.isNoteOn()) {
            if (engine->plugin) {
                engine->plugin->onMidiMessage(msg);
            }
        } else if (msg.isNoteOff()) {
            if (engine->plugin) {
                engine->plugin->onMidiMessage(msg);
            }
        }
    }
    engine->midiQueue.clear(); // 清空已处理的消息
    if (engine->plugin) {
        engine->plugin->process(buffer, bufferSize);
    } else {
        memset(buffer, 0, sizeof(buffer)); // 默认静音
    }
    */
    /*else{
        // 默认静音处理
        memset(ctx->pcmBuffer, 0, sizeof(short) * samplesPerBuffer);
    }*/
    (*bq)->Enqueue(bq,ctx->pcmBuffer,sizeof(short)*samplesPerBuffer);
}
// master音量控制 引擎硬件级别音量控制
void SlEngine::setVolume(float linearGain)
{
    // 1. 钳制输入范围
    linearGain = std::fmax(0.0f, std::fmin(1.0f,linearGain));
    if(!volumeItf){LOGE(enginetag,"Volume interface is invalid!");return;}
    // 3. 计算音量级别（添加四舍五入）
    float dbRange = static_cast<float>(maxLevel - minLevel);
    SLmillibel level = minLevel + static_cast<SLmillibel>(std::round(linearGain * dbRange));

    // 4. 设置音量
    SLresult r = (*volumeItf)->SetVolumeLevel(volumeItf, level);
    if (r != SL_RESULT_SUCCESS) {
        __android_log_print(ANDROID_LOG_ERROR, enginetag, "SetVolumeLevel failed: %d", r);
    }
}
// 歌曲播放控制
void SlEngine::play(){(*playerPlay)->SetPlayState(playerPlay,SL_PLAYSTATE_PLAYING);}
void SlEngine::stop(){(*playerPlay)->SetPlayState(playerPlay,SL_PLAYSTATE_STOPPED);}
void SlEngine::pause(){(*playerPlay)->SetPlayState(playerPlay,SL_PLAYSTATE_PAUSED);}
// 乐器插件管理
// SlEngine.cpp 修改插件加载逻辑 2025/6/1
// 2025/6/2 手动编程
void SlEngine::ChannelRack::ChannelRackAdd(const char* path)
{
    void *handle = dlopen(path,RTLD_LAZY);
    if(!handle) LOGE(enginetag,"句柄获取失败");
    typedef Instrument* (*CreateFunc)();
    auto createFunc = (CreateFunc)dlsym(handle, "createInstrument");
    if (!createFunc) {
        dlclose(handle);
    }

    Instrument* inst = createFunc();
    if (!inst) {
        dlclose(handle);
    }

   // engine.channelRack.push_back({name, handle, inst});

}
void SlEngine::ChannelRack::ChannelRackRemove()
{

}

void SlEngine::setActiveInstrument(int index)
{
}
// 加载插件函数 旧的代码 需要修改
/*
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_xsh_opensltest_SlInstrumentTest_loadPlugin(JNIEnv* env, jobject thiz, jstring pluginPath)
{
    const char* path = env->GetStringUTFChars(pluginPath, nullptr);
    //jboolean result = engine.ChannelRackAdd(path);
    env->ReleaseStringUTFChars(pluginPath, path);
   // return result;
}*/
// 用于自动加载引擎 引擎和插件分离
extern "C" {

JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_initEngine(JNIEnv *env, jobject thiz){engine.initEngine();}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_destoryEngine(JNIEnv *env,jobject thiz){engine.destoryEngine();}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_play(JNIEnv *env, jobject thiz){engine.play();}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_pause(JNIEnv *env, jobject thiz){engine.pause();}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_stop(JNIEnv *env, jobject thiz){engine.stop();}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_renderToFile(JNIEnv *env, jclass clazz, jstring mode,jstring file_type){}
// 每个乐器的单独测试函数
JNIEXPORT jboolean JNICALL Java_com_xsh_opensltest_SlEngine_testLoadOnePlugin(JNIEnv *env,jobject thiz,jstring libpath)
{
    const char* path = env->GetStringUTFChars(libpath, nullptr);
    void *handle = dlopen(path,RTLD_LAZY);
    if(!handle)
    {
        LOGE(enginetag,"句柄获取失败");
        return false;
    }
    typedef Instrument* (*CreateFunc)();
    auto createFunc = (CreateFunc)dlsym(handle, "createInstrument");
    if (!createFunc)
    {
        LOGD(enginetag,"函数创建失败");
        dlclose(handle);
        return false;
    }
    Instrument* inst = createFunc();
    engine.activeInstrument = inst;
    env->ReleaseStringUTFChars(libpath,path);
    return true;
}
//  @param libpath 绝对路径

JNIEXPORT jboolean JNICALL Java_com_xsh_opensltest_SlEngine_loadPlugin(JNIEnv *env, jobject thiz, jstring libpath)
{
    const char* native_path = env->GetStringUTFChars(libpath, nullptr);
    env->ReleaseStringUTFChars(libpath,native_path);
    //return engine.ChannelRackAdd(native_path);
}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_setActiveInstrument(JNIEnv *env, jobject thiz, jint index)
{
    engine.setActiveInstrument(index);
}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_pluginEventHandlerTest(JNIEnv *env,jobject thiz)
{
    LOGD(enginetag,"call from从eventHandler到slengine.cpp");
}
// 这个函数在classesd8.jar里的EventHandler里面调用
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_changeActiveInsParam(JNIEnv *env,jobject thiz,jstring event,jdouble value)
{
    const char* eventName = env->GetStringUTFChars(event,nullptr);
    LOGD(enginetag,"引擎接收到改变当前乐器参数事件:%f",value);
    engine.activeInstrument->onEvent(eventName,value);
    env->ReleaseStringUTFChars(event,eventName);
}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_changeActiveInsParamEnum(JNIEnv *env, jobject thiz, jstring event, jint enum_value)
{
    const char *eventName = env->GetStringUTFChars(event, nullptr);
    env->ReleaseStringUTFChars(event, eventName);
    if (engine.activeInstrument) {
        engine.activeInstrument->onEvent(eventName, enum_value);
    }
}
// 这个函数在PluginPiano的OnPiano里面调用
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_activeNoteOn(JNIEnv *env,jobject thiz,jint midi_note)
{
    // 重点在于这行是否报错 reinerpret
    //engine.activeInstrument->onEvent("noteOn", reinterpret_cast<jobject>(midi_note),env);
    // 在某种情况下报错
    engine.activeInstrument->onEvent("noteOn",midi_note);
    engine.play();
}
JNIEXPORT void JNICALL Java_com_xsh_opensltest_SlEngine_changeActiveInsParamBool(JNIEnv *env,jobject thiz,jstring event_name,jboolean value)
{
    const char *eventName = env->GetStringUTFChars(event_name, nullptr);
    //engine.activeInstrument->onEvent(eventName,value);
    bool on_off = static_cast<bool >(value);
    engine.activeInstrument->onEvent(eventName,on_off);
    env->ReleaseStringUTFChars(event_name,eventName);
}
}